using System.Linq.Expressions;
using MultiAgentsClient.Shared;

namespace MultiAgentsClient.Service.WorkflowEngine;

public class BehaviorTreeContext
{
    public int ChatRoomIdForSession { get; set; } = 0;
    public string BehaviorTreeName { get; set; } = "";
    private Dictionary<string, float> FloatVariables { get; set; } = [];
    private Dictionary<string, string> StringVariables { get; set; } = [];
    private Dictionary<string, int> IntVariables { get; set; } = [];
    private Dictionary<string, List<string>> StrListVariables { get; set; } = [];
    private Dictionary<string, List<LlmMessageSimp>> LlmMsgsVariable { get; set; } = [];

    public bool SetVar<TVar>(string nodeCustomName, string variableName, TVar value)
    {
        string name = nodeCustomName + "." + variableName;
        switch (value)
        {
            case int varValInt:
                IntVariables[name] = varValInt;
                break;
            case float varValFloat:
                FloatVariables[name] = varValFloat;
                break;
            case string varValStr:
                StringVariables[name] = varValStr;
                break;
            case List<LlmMessageSimp> varValMsgs:
                LlmMsgsVariable[name] = varValMsgs;
                break;
            case List<string> varValStrList:
                StrListVariables[name] = varValStrList;
                break;
            default:
                return false;
        }

        return true;
    }

    public bool SetVar<TVar>(string nodeCustomName, Expression<Func<TVar>> expression)
    {
        var memberExpression = (MemberExpression)expression.Body;
        var varName = nodeCustomName + "." + memberExpression.Member.Name;
        var varVal = expression.Compile().Invoke();

        switch (varVal)
        {
            case int varValInt:
                IntVariables[varName] = varValInt;
                break;
            case float varValFloat:
                FloatVariables[varName] = varValFloat;
                break;
            case string varValStr:
                StringVariables[varName] = varValStr;
                break;
            case List<LlmMessageSimp> varValMsgs:
                LlmMsgsVariable[varName] = varValMsgs;
                break;
            case List<string> varValStrList:
                StrListVariables[varName] = varValStrList;
                break;
            default:
                return false;
        }

        return true;
    }

    public bool HasVar<TVar>(string varName)
    {
        var varType = typeof(TVar);
        if (varType == typeof(int))
        {
            return IntVariables.ContainsKey(varName);
        }
        else if (varType == typeof(float))
        {
            return FloatVariables.ContainsKey(varName);
        }
        else if (varType == typeof(string))
        {
            return StringVariables.ContainsKey(varName);
        }
        else if (varType == typeof(List<LlmMessageSimp>))
        {
            return LlmMsgsVariable.ContainsKey(varName);
        }
        else if (varType == typeof(List<string>))
        {
            return StrListVariables.ContainsKey(varName);
        }
        else
        {
            throw new Exception("Not supported");
        }
    }

    public TVar? GetVar<TVar>(string varName)
    {
        if (HasVar<int>(varName) && IntVariables.TryGetValue(varName, out var intVar))
        {
            return (TVar)(object)intVar;
        }
        else if (HasVar<float>(varName) && FloatVariables.TryGetValue(varName, out var floatVar))
        {
            return (TVar)(object)floatVar;
        }
        else if (HasVar<string>(varName) && StringVariables.TryGetValue(varName, out var stringVar))
        {
            return (TVar)(object)stringVar;
        }
        else if (HasVar<List<LlmMessageSimp>>(varName) && LlmMsgsVariable.TryGetValue(varName, out var llmMsgsVar))
        {
            return (TVar)(object)llmMsgsVar;
        }
        else if (HasVar<List<string>>(varName) && StrListVariables.TryGetValue(varName, out var strListVar))
        {
            return (TVar)(object)strListVar;
        }
        else
        {
            return default;
        }
    }
}
